from .Class_SVDObject import *
from .Class_CPU import *
from .Class_Peripheral import *
from xml.dom.minidom import Document as XMLFile

class Device(SVDObject):
    def __init__(self, name: str ="", version: str = "", description: str = "", 
                 addressUnitBits: str = "", width: str = "", 
                 size: str = "", resetValue: str = "", resetMask: str = ""):
        super().__init__(name)
        self.type = "Device"
        self.version = version
        self.description = description
        self.addressUnitBits = addressUnitBits
        self.width = width
        self.size = size
        self.resetValue = resetValue
        self.resetMask = resetMask
        self.father = "TOP"
        self.cpu : CPU = CPU(name="CM0")
        self.Peripherals : List[Peripheral] = []

    def __repr__(self):
        return (f"Device(name={self.name}, version={self.version}, description={self.description}, "
                f"addressUnitBits={self.addressUnitBits}, width={self.width}, "
                f"size={self.size}, resetValue={self.resetValue}, resetMask={self.resetMask})")
    def SetCPU(self, cpu: CPU) :
        cpu.SetFather(self.myself())
        self.cpu = cpu
    
    def SetFather(self, father: str):
        self.father = father
        if self.cpu :
            self.cpu.SetFather(self.myself())
        for per in self.Peripherals:
            per.SetFather(self.myself())
        
    
    def SetDescription(self, description: str):
        self.description = description

    def AddPeripheral(self, peripheral: Peripheral) :
        peripheral.SetFather(self.myself())
        self.Peripherals.append(peripheral)
          
    def ValidCheck(self):        
        errcnt = super().ValidCheck()
        errcnt += self.cpu.ValidCheck();
        for Peripheral in self.Peripherals:
            errcnt += Peripheral.ValidCheck();
        return errcnt
    
    def toString(self, tablevel : int = 0) -> str:
        xml_output = (
            f"{self.TabsString(tablevel)}<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n"
            f"{self.TabsString(tablevel)}<device schemaVersion=\"1.1\"\n"
            f"{self.TabsString(tablevel)}xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
            f"{self.TabsString(tablevel)}xs:noNamespaceSchemaLocation=\"CMSIS-SVD_Schema_1_1.xsd\">\n"
            f"{self.TabsString(tablevel + 1)}<name>{self.name}</name>\n"
            f"{self.TabsString(tablevel + 1)}<version>{self.version}</version>\n"
            f"{self.TabsString(tablevel + 1)}<description>{self.description}</description>\n"
        )
        xml_output += self.cpu.toString(tablevel + 1);            
        xml_output += (
            f"{self.TabsString(tablevel + 1)}<!--Bus Interface Properties-->\n"
            f"{self.TabsString(tablevel + 1)}<addressUnitBits>{self.addressUnitBits}</addressUnitBits>\n"
            f"{self.TabsString(tablevel + 1)}<width>{self.width}</width>\n"
            f"{self.TabsString(tablevel + 1)}<!--Register Default Properties-->\n"
            f"{self.TabsString(tablevel + 1)}<size>{self.size}</size>\n"
            f"{self.TabsString(tablevel + 1)}<resetValue>{self.resetValue}</resetValue>\n"
            f"{self.TabsString(tablevel + 1)}<resetMask>{self.resetMask}</resetMask>\n"
            f"{self.TabsString(tablevel + 1)}<peripherals>\n"
        )
        
        for per in self.Peripherals:
            xml_output += per.toString(tablevel + 2) 
             
        xml_output += (
            f"{self.TabsString(tablevel + 1)}</peripherals>\n"
            f"{self.TabsString(tablevel)}</device>\n"
        )
        return xml_output
    
    def toXmlStr(self) -> str:
        # 创建文档对象      
        return self.toXmlObj().toprettyxml(indent="    ")
    
    def toXmlObj(self):
        
        doc = XMLFile()        
        device_element = doc.createElement('device')
        device_element.setAttribute('schemaVersion', '1.1')
        device_element.setAttribute('xmlns:xs', 'http://www.w3.org/2001/XMLSchema-instance')
        device_element.setAttribute('xs:noNamespaceSchemaLocation', 'CMSIS-SVD_Schema_1_1.xsd')
        
        name_element = doc.createElement('name')
        name_text = doc.createTextNode(self.name)
        name_element.appendChild(name_text)
        device_element.appendChild(name_element)
        
        version_element = doc.createElement('version')
        version_text = doc.createTextNode(str(self.version))
        version_element.appendChild(version_text)
        device_element.appendChild(version_element)
        
        description_element = doc.createElement('description')
        description_text = doc.createTextNode(self.description)
        description_element.appendChild(description_text)
        device_element.appendChild(description_element)
        
        self.cpu.toXmlObj(device_element)
        
        bus_interface_properties_comment = doc.createComment('Bus Interface Properties')
        device_element.appendChild(bus_interface_properties_comment)
        
        address_unit_bits_element = doc.createElement('addressUnitBits')
        address_unit_bits_text = doc.createTextNode(str(self.addressUnitBits))
        address_unit_bits_element.appendChild(address_unit_bits_text)
        device_element.appendChild(address_unit_bits_element)
        
        width_element = doc.createElement('width')
        width_text = doc.createTextNode(str(self.width))
        width_element.appendChild(width_text)
        device_element.appendChild(width_element)
        
        register_default_properties_comment = doc.createComment('Register Default Properties')
        device_element.appendChild(register_default_properties_comment)
        
        size_element = doc.createElement('size')
        size_text = doc.createTextNode(self.size)
        size_element.appendChild(size_text)
        device_element.appendChild(size_element)
        
        reset_value_element = doc.createElement('resetValue')
        reset_value_text = doc.createTextNode(self.resetValue)
        reset_value_element.appendChild(reset_value_text)
        device_element.appendChild(reset_value_element)
        
        reset_mask_element = doc.createElement('resetMask')
        reset_mask_text = doc.createTextNode(self.resetMask)
        reset_mask_element.appendChild(reset_mask_text)
        device_element.appendChild(reset_mask_element)
        
        peripherals_element = doc.createElement('peripherals')
        for per in self.Peripherals:
            per.toXmlObj(peripherals_element)
        device_element.appendChild(peripherals_element)
        
        doc.appendChild(device_element)
        
        return doc
    

    @staticmethod
    def GetTestObject():
        device = Device(
            name="R2406",
            version="1.3",
            description="R2406 CHIP",
            addressUnitBits="8",
            width="32",
            size="0x20",
            resetValue="0x0",
            resetMask="0xFFFFFFFF"
        )
        cpu = CPU.GetTestObject()
        per1 = Peripheral.GetTestObject()
        per2 = Peripheral.GetTestObject()
        device.SetCPU(cpu)
        device.AddPeripheral(per1)
        device.AddPeripheral(per2)
        return device

    @staticmethod
    def TestString() :
        testObject = Device.GetTestObject()
        print(testObject.toString())
        return testObject